﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows8Accelerator.Core.Xaml.Html;

namespace Windows8Accelerator.Core.Xaml.Controls.RichText
{
    public abstract class SuperHtmlNodeVisitor
    {
        public object Parent { get; set; }
        public object NewParent { get; set; }
        public bool VisitChildren { get; set; }
        public static Func<SuperHtmlNode, SuperHtmlNodeVisitor, SuperHtmlNodeVisitor> CreateVisitor { get; set; }
        public List<object> Results { get; private set; }
        public SuperHtmlNode SuperHtmlNode { get; private set; }
        public SuperHtmlNodeVisitor ParentVisitor { get; private set; }
        public SuperHtmlNodeVisitorState State { get; private set; }
        public SuperTextFormat TextFormat { get; private set; }

        protected bool AddLineBreakingIfNecessary()
        {
            if (State.RequiresLineBreaking && State.HasContent)
            {
                Results.Add(RichTextFactoryBase.Instance.NewLineBreak());
                if (State.RequiresDoubleLineBreaking)
                    Results.Add(RichTextFactoryBase.Instance.NewLineBreak());
                State.AllowLeadingSpace = false;
                State.RequiresLeadingSpace = false;
                State.RequiresLineBreaking = false;
                State.RequiresDoubleLineBreaking = false;
                return true;
            }
            return false;
        }

        protected void AddRun(string text)
        {
            Results.Add(RichTextFactoryBase.Instance.NewRun(text, TextFormat));
        }

        protected void AddImage(string imageSrc, double? width, double? height)
        {
            Results.Add(RichTextFactoryBase.Instance.NewImage(imageSrc, width, height));
        }

        protected void AddListItem(int? orderCount, int indentLevel)
        {
            object newParent;
            Results.Add(RichTextFactoryBase.Instance.NewListItem(orderCount, indentLevel, out newParent, State.DefaultTextFormat));
            NewParent = newParent;
        }

        protected void AddA(string href)
        {
            object newParent;
            Results.Add(RichTextFactoryBase.Instance.NewA(href, out newParent, State.AnchorTextFormat, State.OnHyperlinkClick));
            NewParent = newParent;
        }

        static SuperHtmlNodeVisitor()
        {
            CreateVisitor = (node, parent) =>
            {
                if (node.IsText)
                    return new TextVisitor(node, parent);
                switch (node.TagName)
                {
                    case "!doctype":
                    case "applet":
                    case "area":
                    case "audio":
                    case "base":
                    case "basefront":
                    case "button":
                    case "canvas":
                    case "command":
                    case "datalist":
                    case "embed":
                    case "frame":
                    case "frameset":
                    case "hr":
                    case "iframe":
                    case "input":
                    case "kbd":
                    case "keygen":
                    case "link":
                    case "map":
                    case "menu":
                    case "meta":
                    case "meter":
                    case "nav":
                    case "noframes":
                    case "noscript":
                    case "object":
                    case "optgroup":
                    case "option":
                    case "param":
                    case "progress":
                    case "rp":
                    case "rt":
                    case "ruby":
                    case "select":
                    case "source":
                    case "style":
                    case "table":
                    case "tbody":
                    case "td":
                    case "textarea":
                    case "tfoot":
                    case "th":
                    case "thead":
                    case "title":
                    case "tr":
                    case "track":
                    case "tt":
                    case "var":
                    case "video":
                    case "head":
                    case "script":
                        return new ControlVisitor(node, parent);
                    case "b":
                    case "strong":
                    case "em":
                    case "i":
                    case "u":
                        return new FormatVisitor(node, parent);
                    case "br":
                        return new BrVisitor(node, parent);
                    case "h1":
                    case "h2":
                    case "h3":
                    case "h4":
                    case "h5":
                    case "h6":
                    case "p":
                    case "div":
                        return new LineBreakingFormatVisitor(node, parent);
                    case "a":
                        return new AVisitor(node, parent);
                    case "abbr":
                    case "acronym":
                    case "address":
                    case "article":
                    case "aside":
                    case "bdi":
                    case "bdo":
                    case "big":
                    case "blockquote":
                    case "caption":
                    case "center":
                    case "cite":
                    case "code":
                    case "col":
                    case "colgroup":
                    case "dd":
                    case "del":
                    case "details":
                    case "dfn":
                    case "dir":
                    case "dl":
                    case "dt":
                    case "fieldset":
                    case "figcaption":
                    case "figure":
                    case "font":
                    case "footer":
                    case "form":
                    case "header":
                    case "hgroup":
                    case "ins":
                    case "label":
                    case "legend":
                    case "mark":
                    case "output":
                    case "pre":
                    case "q":
                    case "s":
                    case "samp":
                    case "section":
                    case "small":
                    case "span":
                    case "strike":
                    case "sub":
                    case "summary":
                    case "sup":
                    case "time":
                    case "wbr":
                    case "html":
                    case "body":
                    default:
                        return new BodyVisitor(node, parent);
                    case "ol":
                    case "ul":
                        return new ListVisitor(node, parent);
                    case "li":
                        return new ListItemVisitor(node, parent);
                    case "img":
                        return new ImageVisitor(node, parent);
                }
            };
        }

        public SuperHtmlNodeVisitor(SuperHtmlNode superHtmlNode, SuperHtmlNodeVisitor parentVisitor)
        {
            Results = new List<object>();
            SuperHtmlNode = superHtmlNode;
            ParentVisitor = parentVisitor;
            if (parentVisitor != null)
            {
                Parent = parentVisitor.NewParent ?? parentVisitor.Parent;
                State = parentVisitor.State;
                if (parentVisitor.TextFormat != null)
                    TextFormat = parentVisitor.TextFormat.Clone();
            }
            else
            {
                State = new SuperHtmlNodeVisitorState();
            }

            if (TextFormat == null)
                TextFormat = new SuperTextFormat();
        }

        public void Visit()
        {
            InternalVisitNode(SuperHtmlNode);

            foreach (var result in Results)
                AddToParent(result);

            if (VisitChildren)
            {
                foreach (var node in SuperHtmlNode.GetChildNodes())
                {
                    CreateVisitor(node, this).Visit();
                }
            }

            InternalPosVisitNode(SuperHtmlNode);
        }

        protected virtual void InternalPosVisitNode(SuperHtmlNode SuperHtmlNode) { }

        private void AddToParent(object result)
        {
            RichTextFactoryBase.Instance.AddToParent(Parent, result, this);
        }

        protected abstract void InternalVisitNode(SuperHtmlNode htmlNode);
    }
}
